package godzilla.ciudad.estructuras;

import godzilla.ciudad.recursos.ListaDeRecursos;
import godzilla.ciudad.recursos.Recurso;

import java.util.Iterator;

import org.json.JSONObject;
import org.json.JSONString;

public abstract class Estructura implements JSONString {


	protected ListaDeRecursos listaDeRecursosOfrecidos;
	protected ListaDeRecursos listaDeRecursosUtilizados;
	protected ListaDeRecursos listaDeNecesidades;
	protected ListaDeRecursos listaDeRecursosQuePermiteAcceder;
	protected ListaDeRecursos listaDeRecursosPropagables;
	protected int costo;
	protected String nombre;
	protected int salud;
	

	
	public Estructura(){
		
		this.listaDeRecursosOfrecidos = new ListaDeRecursos();
		this.listaDeRecursosUtilizados = new ListaDeRecursos();
		this.listaDeNecesidades = new ListaDeRecursos();
		this.listaDeRecursosQuePermiteAcceder = new ListaDeRecursos();
		this.listaDeRecursosPropagables = new ListaDeRecursos();
		
		this.salud=this.saludMaxima();
		
		this.definirNecesidadesYOfertas();
		this.definirCostoYVelocidadDeReparacion();
		this.definirNombre();
		
	}
	
	protected abstract void definirNombre();

	protected abstract void definirCostoYVelocidadDeReparacion();

	protected abstract void definirNecesidadesYOfertas();
	
	public boolean utilizar(Recurso recursoAUtilizar) {

		if (recursoAUtilizar.seraUtilizadoPor(this)){
			listaDeRecursosUtilizados.agregar(recursoAUtilizar);
			return true;
		}
		return false;
		
	}
	
	public ListaDeRecursos provee() {
		return this.listaDeRecursosOfrecidos;
	}

	
	public boolean necesidadesSatisfechas() {
		
		return this.listaDeRecursosUtilizados.contieneEstaLista(this.listaDeNecesidades);
		
		
	}
	
	public ListaDeRecursos necesidades(){
		return this.listaDeNecesidades;
	}
	

	public ListaDeRecursos serviciosAccesiblesDesdeAqui() {
		return listaDeRecursosQuePermiteAcceder;
	}
	
	public boolean proveeAccesoA(Recurso recursoBuscado) {
		
		return this.listaDeRecursosQuePermiteAcceder.contiene(recursoBuscado);
		
	}

	public boolean proveeEsteRecurso( Recurso recursoBuscado) {
		
		return this.listaDeRecursosOfrecidos.contiene(recursoBuscado);
		
		
	}

	public abstract boolean esSubterranea();

	public abstract boolean seConstruyeSobreAgua();
	
	public int costo(){
		return costo;
	}

	public ListaDeRecursos listaDeRecursosUtilizados() {

		return this.listaDeRecursosUtilizados;
	}

	public ListaDeRecursos listaDeRecursosQuePermiteAcceder() {

		return this.listaDeRecursosQuePermiteAcceder;
		
	}

	public boolean permitePropagar(Recurso recurso) {

		return this.listaDeRecursosPropagables.contiene(recurso);
		
	}

	public void obtenerRecursosDe(Estructura otraEstructura) {

		Iterator<Recurso> iterador = this.listaDeNecesidades.iterador();
		while (iterador.hasNext()){
			Recurso recursoBuscado = iterador.next();
			if (otraEstructura.listaDeRecursosQuePermiteAcceder.contiene(recursoBuscado) && !this.listaDeRecursosUtilizados.contiene(recursoBuscado)){
				this.utilizar(otraEstructura.listaDeRecursosQuePermiteAcceder.extraerRecurso(recursoBuscado));
	
			}
		}
		

		
	}

	public void removerRecursosPropagados() {

		this.listaDeRecursosQuePermiteAcceder.vaciar();
		
	}

	public int recolectarImpuestos() {

		if (this.necesidadesSatisfechas()) return calcularImpuestos();
		else return 0;
	}

	protected abstract int calcularImpuestos();
	

	public int salud() {
		return this.salud;
	}

	public void daniarse(int danioACausar) {

		salud = salud - danioACausar;
		
	}
	
	public void serDaniadoPorGodzilla(){
		
		daniarse(this.danioCausadoPorGodzilla());
		
	}

	protected abstract int danioCausadoPorGodzilla();

	public void removerRecursosAsignados() {
		

		this.listaDeRecursosUtilizados.vaciar();
		
	}

	public Estructura duplicar() {
		Estructura duplicado = duplicadoDeEstaEstructura();
		duplicado.salud = this.salud;
		return duplicado;
	}

	protected abstract Estructura duplicadoDeEstaEstructura();

	public boolean enPie() {
		return (salud > 0);
	}

	public abstract boolean puedeRepararEstructuras();
	
	public String nombre() {
		return nombre;
	}
	
	public String toJSONString() {
		
		JSONObject objetoJSON = new JSONObject();
		objetoJSON.put("Nombre",this.nombre);
		objetoJSON.put("Salud", this.salud());
		
		return objetoJSON.toString();
		
	}


	public static Estructura obtenerObjetoDesdeJSON(String stringJSON) {

		Estructura estructuraADevolver = null;
		JSONObject objetoJSON = new JSONObject(stringJSON);
		estructuraADevolver = generarEstructuraDesde(objetoJSON);
		estructuraADevolver.salud=objetoJSON.getInt("Salud");
		return estructuraADevolver;
	}


	private static Estructura generarEstructuraDesde(JSONObject estructuraJSON) {
		
		Estructura estructuraGenerada = BaseDeDatosEstructuras.reconocerEstructura(estructuraJSON);
		
		return estructuraGenerada;
	}

	public int saludMaxima() {
		return 100;
	}

	public void repararse() {
		if (this.salud + this.porcentajeDeReparacion() > this.saludMaxima()){
			this.salud = this.saludMaxima();
		}
		else {
			this.salud = this.salud + this.porcentajeDeReparacion();
		}
		
	}

	protected abstract int porcentajeDeReparacion();
	
	
	
	
	
}
